/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { pickedFaceData, pickedLineData, pickedVertexData } from '@amcax/base';
import {
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-cad/common/components/command-form/constants';
import { NonDialogPickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { RJSFSchema } from '@rjsf/utils';
import { useAsyncEffect } from 'ahooks';
import { isEmpty, omitBy } from 'lodash';
import { useEffect, useMemo, useState } from 'react';
import { ChildLineCommandProps } from './types';
import ReverseIconWidget from '@app-cad/common/RJSFWidgets/ReverseIconWidget';
import { usePointContext } from './PointContext';
import { ctx2 } from '@app-base/module';

type pickedDirection = pickedLineData | pickedFaceData;
//"dismode": "len" or "dis" or "per",

type FormDataType = {
  dismode: string;
  startPoint: pickedVertexData;
  distanceLen: number; // 距离模式下的长度
  distanceDir: number; // 方向模式上的长度
  rate: number;
  curve?: pickedLineData;
  vector?: pickedDirection;
  reverseDir?: boolean;
};

// 点在曲线上
export function PointCurve({
  onClose,
  props,
  editDxid,
}: ChildLineCommandProps) {
  const [formData, setFormData] = useState<FormDataType>({
    dismode: 'len',
    startPoint: undefined,
    curve: undefined,
    distanceLen: 0,
    distanceDir: 0,
    rate: 0.5,
    vector: undefined,
    reverseDir: false,
  });

  const { picker } = useTools();
  const { setSharedPoint } = usePointContext();
  const [curveInfo, setCurveInfo] = useState({
    dxid: '',
    length: -1,
  });

  useEffect(() => {
    excuteData();
  }, [formData]);

  useAsyncEffect(async () => {
    if (props) {
      const startPoint = props?.params?.point;
      const curve = props?.params?.curve;
      const disval = props?.params?.disval;
      const vector = props?.params?.vector;
      const dismode = props ? props?.params?.dismode : 'len';

      await initEditDependency([startPoint, curve, vector]);

      const defaultPoint = picker.generatePickObjByPickID(
        startPoint,
      ) as pickedVertexData;
      const defaultVector = vector
        ? (picker.generatePickObjByPickID(vector) as pickedDirection)
        : undefined;
      const defaultCurve = picker.generatePickObjByPickID(
        curve,
      ) as pickedLineData;

      setFormData({
        dismode: dismode,
        startPoint: defaultPoint,
        curve: defaultCurve,
        distanceLen: dismode === 'len' ? disval : 0,
        distanceDir: dismode === 'dis' ? disval : 0,
        rate: dismode === 'per' ? disval : 0,
        vector: defaultVector,
        reverseDir: props?.params?.reverse ? true : false,
      });
    }
  }, [editDxid]);

  const isFormDataValid = () => {
    const { curve } = formData;

    if (isEmpty(curve)) {
      return false;
    }

    return true;
  };

  const checkAndFinishDraw = async () => {
    if (!isFormDataValid()) {
      return;
    }

    await excuteData(false);
    onClose();
  };

  const {
    previewCmdResult,
    initEditDependency,
    initingEdit,
    isLoading,
    clear,
    confirmCommand,
  } = useCommand('cmd-curve-point', {
    onClose,
    finishDraw: checkAndFinishDraw,
    commandName: 'CreateVertex',
    editDxid: editDxid || props?.shape,
  });

  useEffect(() => {
    const pointdata = previewCmdResult?.data?.[0]?.points?.[0];
    if (pointdata) {
      setSharedPoint(pointdata);
    } else {
      setSharedPoint(null);
    }
  }, [previewCmdResult]);

  const excuteData = async (preview: boolean = true) => {
    const {
      startPoint,
      vector,
      dismode,
      distanceLen,
      distanceDir,
      rate,
      curve,
      reverseDir,
    } = formData;

    if (!isFormDataValid()) {
      clear();
      return;
    }

    // 如果曲线变更，则重新获取长度
    if (formData.curve.edgeId !== curveInfo.dxid) {
      const result = await ctx2.commandCenters.curveCommands.getCurveLength(
        curve.edgeId,
      );
      setCurveInfo({
        dxid: curve.edgeId,
        length: result?.length || -1,
      });
    }

    // 仅 dismode === 'per' 时，reverse 是有效的，其他情况，通过将 disval 取负值来实现反向
    const disval =
      dismode === 'per' ? rate : dismode === 'len' ? distanceLen : distanceDir;
    const vectorId = vector
      ? (vector as pickedFaceData)?.meshId || (vector as pickedLineData)?.edgeId
      : undefined;

    const allParma = {
      a: {
        mode: 'oncurve',
        point: startPoint?.vertexId,
        curve: curve.edgeId,
        disval: disval,
        vector: dismode === 'dis' ? vectorId : undefined,
        dismode: dismode,
        reverse: dismode === 'per' ? reverseDir : undefined,
      },
      p: preview,
    };

    await confirmCommand(allParma, preview);
  };

  const schema: RJSFSchema = useMemo(() => {
    const { dismode } = formData;
    const properties = omitBy(
      {
        curve: {
          type: 'string',
          title: '曲线',
          format: PickInputRJSFFormat.PickCurve,
        },
        dismode: {
          type: 'string',
          title: '与参考点的距离',
          default: dismode,
          oneOf: [
            {
              type: 'string',
              title: '沿曲线的距离',
              const: 'len',
            },
            {
              type: 'string',
              title: '沿方向的距离',
              const: 'dis',
            },
            {
              type: 'string',
              title: '曲线长度比率',
              const: 'per',
            },
          ],
        },
        vector: dismode === 'dis' && {
          type: 'string',
          title: '方向',
          format: PickInputRJSFFormat.PickDirection,
        },
        distanceLen:
          dismode === 'len'
            ? {
                type: 'number',
                title: '偏移',
                default: 0,
                format: NumberInputFormat.Length,
              }
            : null,
        distanceDir:
          dismode === 'dis'
            ? {
                type: 'number',
                title: '偏移',
                default: 0,
                format: NumberInputFormat.Length,
              }
            : null,
        rate:
          dismode === 'per'
            ? {
                type: 'number',
                title: '比率',
                default: 0,
                multipleOf: 0.1,
                minimum: 0,
              }
            : null,
        reverseDir:
          dismode === 'per'
            ? {
                type: 'boolean',
                title: '反向',
              }
            : null,
        startPoint: {
          type: 'string',
          title: '参考点',
          format: PickInputRJSFFormat.PickVertex,
        },
      },
      (val) => val == null,
    );

    return {
      type: 'object',
      properties,
    } as RJSFSchema;
  }, [formData.dismode]);

  const getExtraUiSchema = () => {
    return {
      // dismode: {
      //   'ui:widget': 'radio',
      //   'ui:classNames': 'form-group-horizontal',
      // },
      startPoint: {
        'ui:placeholder': '默认为曲线的起点',
      },
      distanceLen: {
        'ui:placeholder': '请输入距离',
      },
      distanceDir: {
        'ui:placeholder': '请输入距离',
      },
      rate: {
        'ui:placeholder': '请输入比率',
      },
      reverseDir: {
        'ui:classNames': 'plane-offset-form-reverse-direction',
        'ui:widget': 'reverseIcon',
        'ui:label': false,
      },
      vector: {
        'ui:placeholder': '请输入平面或直线',
        'ui:options': {
          allowInfinitePlane: true,
        },
      },
      curve: {
        'ui:placeholder': '请输入曲线',
        'ui:autofocus': true,
        'ui:options': {
          showArrow: true,
          // curveReversable: true,
        },
      },
    };
  };

  return (
    <NonDialogPickableCommandForm
      className='-mt-3'
      onCancel={onClose}
      disabled={initingEdit}
      submitLoading={isLoading}
      isFormDataValid={isFormDataValid()}
      schema={schema}
      formData={formData}
      onChange={(v) => {
        /**
         * 当用户从“曲线上的距离”切换至“曲线长度比率”时，比率一栏会根据“曲线上的距离”下填的长度值，自动换算成比率值，并填写在比率输入框内
         */
        if (v.dismode !== formData.dismode) {
          if (v.dismode === 'dis') {
            v.distanceLen = 0; // 切换到方向模式时，清空长度
            v.rate = 0; // 切换到方向模式时，清空比率
            v.reverseDir = false; // 切换到方向模式时，清空反向选项
          } else if (v.dismode === 'len' && formData.dismode === 'per') {
            v.distanceDir = 0; // 切换到长度模式时，清空方向

            if (v.startPoint) {
              // 如果选择参考点时，目前无法转换，设为默认值
              v.distanceLen = 0;
            } else if (
              v.curve &&
              curveInfo.length > 0 &&
              v.curve.edgeId === curveInfo.dxid
            ) {
              if (v.reverseDir) {
                v.distanceLen = curveInfo.length * (1 - v.rate);
              } else {
                v.distanceLen = curveInfo.length * v.rate;
              }
            }
          } else if (v.dismode === 'per' && formData.dismode === 'len') {
            v.distanceDir = 0; // 切换到长度模式时，清空方向

            if (v.distanceLen < 0) {
              // 如果长度小于0，不做转换，设置为默认值。
              v.rate = 0;
            } else if (v.startPoint) {
              // 如果选择参考点时，目前无法转换，设为默认值
              v.rate = 0;
            } else if (
              v.curve &&
              curveInfo.length > 0 &&
              v.curve.edgeId === curveInfo.dxid
            ) {
              v.rate = v.distanceLen / curveInfo.length;
              v.reverseDir = false;
            }
          }
        }

        setFormData(v);
      }}
      widgets={{
        reverseIcon: ReverseIconWidget,
      }}
      extraUiSchema={getExtraUiSchema()}
      submitText='完成'
      onSubmit={checkAndFinishDraw}
    />
  );
}
